package com.kdgc.energy.dmm.entity;

import com.kdgc.energy.dmm.lambda.Lambda;
import com.kdgc.energy.dmm.util.NameUtil;
import lombok.Getter;
import lombok.Setter;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 实体类信息
 * <p>
 * 包含：class、表名、表别名、类字段与表字段及别名的关联关系
 *
 * @author xu.wenchang
 * @version 1.0 2022/04/14
 */
@Getter
@Setter
public class EntityInfo {
    /**
     * 实体类
     */
    private Class<?> entityClass;
    
    /**
     * 表名
     */
    private String tableName;
    
    /**
     * 字段列映射
     */
    private Map<String, Tuple> fieldColumnMap;
    
    /**
     * 根据方法名查找字段信息
     */
    public String findFieldName(Lambda lambda) {
        String methodName = lambda.getMethodName();
        String fieldName = this.findByMethodName(methodName);
        
        if (null == fieldName) {
            throw new RuntimeException("类" + lambda.getClassName() + "的方法" + lambda.getMethodName() + "未配置JPA注解信息");
        }
        
        return fieldName;
    }
    
    /**
     * 根据方法名查找字段信息
     */
    private String findByMethodName(String methodName) {
        if (null == this.fieldColumnMap) {
            throw new RuntimeException(entityClass.getName() + "的表字段信息未初始化.");
        }
        
        String fieldName = NameUtil.methodName2FieldName(methodName);
        Tuple tuple = this.fieldColumnMap.get(fieldName);
        return tuple == null ? null : tuple.getColumnName();
    }
    
    public void addFieldInfo(Collection<FieldInfo> collection) {
        if (null == fieldColumnMap) {
            this.fieldColumnMap = new LinkedHashMap<>();
        }
        
        for (FieldInfo fi : collection) {
            String fieldName = fi.getField()
                                 .getName();
            this.fieldColumnMap.compute(fieldName, (k, v) -> {
                if (null == v) {
                    v = new Tuple();
                }
                
                v.setColumnName(fi.getColumnName());
                v.setType(fi.getField()
                            .getType());
                v.setPk(fi.isPk());
                return v;
            });
        }
    }
    
    public void addMethodInfo(Collection<MethodInfo> collection) {
        if (null == fieldColumnMap) {
            this.fieldColumnMap = new LinkedHashMap<>();
        }
        
        for (MethodInfo mi : collection) {
            String methodName = mi.getMethod()
                                  .getName();
            String fieldName = NameUtil.methodName2FieldName(methodName);
            
            if (this.fieldColumnMap.containsKey(fieldName) && !this.fieldColumnMap.get(fieldName)
                                                                                  .getColumnName()
                                                                                  .equals(mi.getColumnName())) {
                throw new RuntimeException("类" + this.entityClass.getName() + "列名定义不一致" + mi.getColumnName() + "!=" + this.fieldColumnMap.get(fieldName)
                                                                                                                                         .getColumnName());
            }
            
            this.fieldColumnMap.compute(fieldName, (k, v) -> {
                if (null == v) {
                    v = new Tuple();
                }
                v.setColumnName(mi.getColumnName());
                
                if (methodName.startsWith("get")) {
                    v.setType(mi.getMethod()
                                .getReturnType());
                } else {
                    if (mi.getMethod()
                          .getParameterCount() == 0) {
                        throw new RuntimeException(mi.getMethod()
                                                     .getName() + "缺少参数");
                    }
                    
                    v.setType(mi.getMethod()
                                .getParameters()[0].getType());
                }
                
                v.setPk(mi.isPk());
                return v;
            });
        }
    }
    
    @Getter
    @Setter
    public static class Tuple {
        String columnName;
        Class<?> type;
        boolean isPk;
    }
}
